#include "AccountManager.h"
#include <XMPPConnection.h>
#include <SmackConfiguration.h>
#include <PacketCollector.h>

#include <packet/IQ.h>
#include <packet/Registration.h>

#include <filter/AndFilter.h>
#include <filter/PacketIDFilter.h>
#include <filter/PacketTypeFilter.h>

#include <util/StringUtils.h>

AccountManager::AccountManager(XMPPConnection * conn) :
	connection(conn),
	info(NULL)
{}

bool AccountManager::supportsAccountCreation() {
    // Check if we already know that the server supports creating new accounts
    if (accountCreationSupported) {
    	return true;
    }
    // No information is known yet (e.g. no stream feature was received from the server
    // indicating that it supports creating new accounts) so send an IQ packet as a way
    // to discover if this feature is supported
    if (info == NULL) {
    	getRegistrationInfo();
IQ::TYPE t = info->getType();
       	accountCreationSupported = (info->getType() != IQ::IQ_TYPE_ERROR);
    }
    return accountCreationSupported;
}

std::vector<std::string> AccountManager::getAccountAttributes() {
    if (info == NULL) {
        getRegistrationInfo();
    }
	std::map<std::string, std::string> attributes = info->getAttributes();
	std::vector<std::string> attKeySet;
	for(std::map<std::string, std::string>::iterator it = attributes.begin();
			it != attributes.end(); ++it) {
		attKeySet.push_back(it->first);
	}
    return attKeySet;
}

std::string AccountManager::getAccountAttribute(std::string & name) {
	if (info == NULL) {
    	getRegistrationInfo();
    }
    return info->getAttributes()[name];
}

std::string AccountManager::getAccountInstructions() {
	if (info == NULL) {
    	getRegistrationInfo();
    }
    return info->getInstructions();
}

void AccountManager::createAccount(std::string & username, std::string & password) {
    if (!supportsAccountCreation()) {
    	//throw new XMPPException("Server does not support account creation.");
    }
    // Create a map for all the required attributes, but give them blank values.
	std::map<std::string, std::string> attributes;
	std::vector<std::string> accountAttributes = getAccountAttributes();
    for (std::vector<std::string>::iterator it = accountAttributes.begin(); it != accountAttributes.end(); ++it) {
    	attributes[*it] = "";
    }
	createAccount(username, password, attributes);
}

void AccountManager::createAccount(std::string & username, std::string & password, std::map<std::string, std::string> & attributes)
{
    if (!supportsAccountCreation()) {
    	//throw new XMPPException("Server does not support account creation.");
    }
    Registration * reg = new Registration();
    reg->setType(IQ::IQ_TYPE_SET);
    reg->setTo(connection->getServiceName());
	attributes["username"] = username;
    attributes["password"] = password;
    reg->setAttributes(attributes);
    PacketFilter * filter = new AndFilter(new PacketIDFilter(reg->getPacketID()),
			new PacketTypeFilter(typeid(IQ))); //TODO
    PacketCollector * collector = connection->createPacketCollector(filter);
    connection->sendPacket(reg);
    IQ * result = dynamic_cast<IQ *>(collector->nextResult(SmackConfiguration::getPacketReplyTimeout()));
    // Stop queuing results
    collector->cancel();
    if (result == NULL) {
    	//throw new XMPPException("No response from server.");
    } else if (result->getType() == IQ::IQ_TYPE_ERROR) {
        //throw new XMPPException(result.getError());
    }
}

void AccountManager::changePassword(std::string & newPassword) {
    Registration * reg = new Registration();
    reg->setType(IQ::IQ_TYPE_SET);
    reg->setTo(connection->getServiceName());
	std::map<std::string, std::string> attributes;
    attributes["username"] = StringUtils::parseName(connection->getUser());
    attributes["password"] = newPassword;
    reg->setAttributes(attributes);
	PacketFilter * filter = new AndFilter(new PacketIDFilter(reg->getPacketID()),
			new PacketTypeFilter(typeid(IQ))); //TODO
    PacketCollector * collector = connection->createPacketCollector(filter);
    connection->sendPacket(reg);
    IQ * result = dynamic_cast<IQ *>(collector->nextResult(SmackConfiguration::getPacketReplyTimeout()));
    // Stop queuing results
    collector->cancel();
    if (result == NULL) {
    	//throw new XMPPException("No response from server.");
    } else if (result->getType() == IQ::IQ_TYPE_ERROR) {
    	//throw new XMPPException(result.getError());
    }
}

void AccountManager::deleteAccount() {
    if (!connection->isAuthenticated()) {
    	//throw new IllegalStateException("Must be logged in to delete a account.");
    }
    Registration * reg = new Registration();
    reg->setType(IQ::IQ_TYPE_SET);
    reg->setTo(connection->getServiceName());
	std::map<std::string, std::string> attributes;
    // To delete an account, we add a single attribute, "remove", that is blank.
    attributes["remove"] = "";
    reg->setAttributes(attributes);
    PacketFilter * filter = new AndFilter(new PacketIDFilter(reg->getPacketID()),
			new PacketTypeFilter(typeid(IQ)));
    PacketCollector * collector = connection->createPacketCollector(filter);
    connection->sendPacket(reg);
    IQ * result = dynamic_cast<IQ *>(collector->nextResult(SmackConfiguration::getPacketReplyTimeout()));
    // Stop queuing results
    collector->cancel();
    if (result == NULL) {
    	//throw new XMPPException("No response from server.");
    } else if (result->getType() == IQ::IQ_TYPE_ERROR) {
    	//throw new XMPPException(result.getError());
    }
}

void AccountManager::getRegistrationInfo() {
    Registration * reg = new Registration();
    reg->setTo(connection->getServiceName());
    PacketFilter * filter = new AndFilter(new PacketIDFilter(reg->getPacketID()),
			new PacketTypeFilter(typeid(IQ)));
    PacketCollector * collector = connection->createPacketCollector(filter);
    connection->sendPacket(reg);
    IQ * result = dynamic_cast<IQ *>(collector->nextResult(SmackConfiguration::getPacketReplyTimeout()));
    // Stop queuing results
    collector->cancel();
    if (result == NULL) {
    	//throw new XMPPException("No response from server.");
    } else if (result->getType() == IQ::IQ_TYPE_ERROR) {
    	//throw new XMPPException(result.getError());
    } else {
    	info = (Registration*)result;
    }
}

